﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Plumbing;
using YArchitech.Revit;

namespace YArchitech.Plumbing
{
	public class CheckMouthHelper
	{
		public CheckMouthHelper(Pipe rPipe)
		{
			this.riserPipe = rPipe;
			this.doc = this.riserPipe.Document;
		}

		public List<Pipe> GetConnRiserPipe()
		{
			List<Pipe> list = new List<Pipe>();
			list.Add(this.riserPipe);
			foreach (Connector conn in this.GetConnectors(this.riserPipe))
			{
				this.GetNextElement(conn, ref list);
			}
			return list;
		}

		private void GetNextElement(Connector conn, ref List<Pipe> listPipe)
		{
			if (conn == null)
			{
				return;
			}
			Connector connectConnector = YJKRevitTools.GetConnectConnector(conn);
			if (connectConnector == null)
			{
				return;
			}
			Element owner = connectConnector.Owner;
			List<Connector> list = new List<Connector>();
			if (owner is Pipe)
			{
				list = this.GetConnectors(owner as Pipe);
				listPipe.Add(owner as Pipe);
			}
			else if (owner is FamilyInstance)
			{
				list = this.GetElementConnectors(owner);
			}
			Connector conn2 = null;
			foreach (Connector connector in list)
			{
				if (connector.CoordinateSystem.BasisZ.IsAlmostEqualTo(-1.0 * connectConnector.CoordinateSystem.BasisZ))
				{
					conn2 = connector;
				}
			}
			this.GetNextElement(conn2, ref listPipe);
		}

		private List<Connector> GetConnectors(Pipe pipe)
		{
			List<Connector> list = new List<Connector>();
			ConnectorSetIterator connectorSetIterator = pipe.ConnectorManager.Connectors.ForwardIterator();
			while (connectorSetIterator.MoveNext())
			{
				object obj = connectorSetIterator.Current;
				Connector connector = obj as Connector;
				if (connector != null && 1 == (int)connector.ConnectorType)
				{
					list.Add(connector);
				}
			}
			return list;
		}

		private List<Connector> GetElementConnectors(Element elem)
		{
			List<Connector> list = new List<Connector>();
			if (elem is FamilyInstance)
			{
				ConnectorSetIterator connectorSetIterator = (elem as FamilyInstance).MEPModel.ConnectorManager.Connectors.ForwardIterator();
				while (connectorSetIterator.MoveNext())
				{
					object obj = connectorSetIterator.Current;
					Connector connector = obj as Connector;
					if (connector != null && connector.Domain == (Autodesk.Revit.DB.Domain)3)
					{
						list.Add(connector);
					}
				}
			}
			return list;
		}

		private List<XYZ> GetPipeEndPoints(Pipe pipe)
		{
			List<XYZ> list = new List<XYZ>();
			List<Connector> connectors = this.GetConnectors(pipe);
			XYZ origin = connectors[0].Origin;
			XYZ origin2 = connectors[1].Origin;
			if (origin.Z > origin2.Z)
			{
				list.Add(origin2);
				list.Add(origin);
			}
			else
			{
				list.Add(origin);
				list.Add(origin2);
			}
			return list;
		}

		private double GetPipeMiddleZValue(Pipe pipe)
		{
			List<XYZ> pipeEndPoints = this.GetPipeEndPoints(pipe);
			return (pipeEndPoints[0].Z + pipeEndPoints[1].Z) / 2.0;
		}

		private List<Pipe> GetOrderPipes(List<Pipe> listPipe)
		{
			List<Pipe> list = new List<Pipe>();
			Pipe pipe = null;
			using (List<Pipe>.Enumerator enumerator = listPipe.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					pipe = enumerator.Current;
					double pipeMiddleZValue = this.GetPipeMiddleZValue(pipe);
					foreach (Pipe pipe2 in listPipe)
					{
						if (!(pipe.Id.ToString() == pipe2.Id.ToString()) && pipeMiddleZValue < this.GetPipeMiddleZValue(pipe2))
						{
							pipe = pipe2;
						}
					}
					list.Add(pipe);
				}
			}
			return list;
		}

		private List<double> GetAllLevel()
		{
			IEnumerable<Element> enumerable = new FilteredElementCollector(this.doc).OfClass(typeof(Level)).ToElements();
			List<Level> list = new List<Level>();
			List<double> list2 = new List<double>();
			foreach (Element element in enumerable)
			{
				if (element is Level && element != null)
				{
					list.Add(element as Level);
					Level level = element as Level;
					list2.Add(level.Elevation);
				}
			}
			new List<double>();
			return (from r in list2
			orderby r
			select r).ToList<double>();
		}

		public bool LayCheckMouth(Pipe pipe, FamilySymbol fs, double zValue, ref List<Pipe> listPipe, XYZ baseVec = null)
		{
			Document document = pipe.Document;
			List<Pipe> list = new List<Pipe>();
			YJKPiping<Pipe> hypiping = new YJKPiping<Pipe>(pipe);
			pipe.Id.ToString();
			XYZ xyz = this.GetPipeEndPoints(pipe)[0];
			xyz = new XYZ(xyz.X, xyz.Y, zValue);
			list = hypiping.Separate(xyz);
			YJKRotateFamilyInstance hyrotateFamilyInstance = new YJKRotateFamilyInstance();
			hyrotateFamilyInstance.MovePiping(list[0]);
			hyrotateFamilyInstance.MovePiping(list[1]);
			YJKPiping<Pipe> hypiping2 = new YJKPiping<Pipe>(list[0]);
			YJKPiping<Pipe> hypiping3 = new YJKPiping<Pipe>(list[1]);
			Connector closeConnector = hypiping2.GetCloseConnector(xyz, false);
			Connector closeConnector2 = hypiping3.GetCloseConnector(xyz, false);
			UnifiedModified.ActivateFamilySymbol(fs);
			FamilyInstance familyInstance = document.Create.NewFamilyInstance(xyz, fs, (Autodesk.Revit.DB.Structure.StructuralType)0);
			document.Regenerate();
			hyrotateFamilyInstance.MoveFamilyInstance(familyInstance, new XYZ(1.0, 0.0, 0.0) * 5.0 / 304.8);
			if (familyInstance.GetParameter("入口直径") != null && !familyInstance.GetParameter("入口直径").IsReadOnly)
			{
				familyInstance.GetParameter("入口直径").Set((closeConnector.Owner as Pipe).Diameter);
			}
			if (baseVec != null && !baseVec.IsAlmostEqualTo(new XYZ(0.0, 0.0, 0.0), 0.0001))
			{
				XYZ handOrientation = familyInstance.HandOrientation;
				double twoXYVectorAngle = YJKRevitTools.GetTwoXYVectorAngle(handOrientation, baseVec);
				hyrotateFamilyInstance.RotateElem(document, familyInstance, twoXYVectorAngle * 180.0 / Math.PI);
				document.Regenerate();
				handOrientation = familyInstance.HandOrientation;
				int num = 0;
				while (!handOrientation.IsAlmostEqualTo(baseVec, 0.0001))
				{
					num++;
					handOrientation = familyInstance.HandOrientation;
					hyrotateFamilyInstance.RotateElem(document, familyInstance, (Math.PI - twoXYVectorAngle) * 360.0 / Math.PI);
					if (num > 4)
					{
						break;
					}
				}
			}
			List<Connector> elementAllConnector = YJKRevitTools.GetElementAllConnector(familyInstance);
			if (elementAllConnector[0].Origin.Z > elementAllConnector[1].Origin.Z)
			{
				if (this.GetPipeMiddleZValue(list[0]) > this.GetPipeMiddleZValue(list[1]))
				{
					elementAllConnector[0].ConnectTo(closeConnector);
					elementAllConnector[1].ConnectTo(closeConnector2);
				}
				else
				{
					elementAllConnector[0].ConnectTo(closeConnector2);
					elementAllConnector[1].ConnectTo(closeConnector);
				}
			}
			else if (this.GetPipeMiddleZValue(list[0]) < this.GetPipeMiddleZValue(list[1]))
			{
				elementAllConnector[0].ConnectTo(closeConnector);
				elementAllConnector[1].ConnectTo(closeConnector2);
			}
			else
			{
				elementAllConnector[0].ConnectTo(closeConnector2);
				elementAllConnector[1].ConnectTo(closeConnector);
			}
			hyrotateFamilyInstance.MoveFamilyInstance(familyInstance, new XYZ(1.0, 0.0, 0.0) * 5.0 / 304.8);
			listPipe.Remove(pipe);
			listPipe.Add(list[0]);
			listPipe.Add(list[1]);
			return true;
		}

		public string LayCheckMouth(List<Pipe> listPipe, FamilySymbol fs, double baseDistance, int floorNum, XYZ baseVec = null)
		{
			string result = "";
			List<double> allLevel = this.GetAllLevel();
			List<double> enableLevel = this.GetEnableLevel(listPipe, allLevel, baseDistance);
			if (enableLevel.Count >= 1)
			{
				this.LayCheckMouth(ref listPipe, fs, enableLevel[0], baseDistance, baseVec);
				if (enableLevel.Count > 1)
				{
					this.LayCheckMouth(ref listPipe, fs, enableLevel[enableLevel.Count - 1], baseDistance, baseVec);
					int i = 0;
					while (i < enableLevel.Count - 1)
					{
						if (i == 0)
						{
							i += floorNum;
						}
						else
						{
							this.LayCheckMouth(ref listPipe, fs, enableLevel[i], baseDistance, baseVec);
							i += floorNum;
						}
					}
				}
			}
			return result;
		}

		private List<double> GetEnableLevel(List<Pipe> listPipe, List<double> listLevel, double baseDistance)
		{
			List<double> list = new List<double>();
			foreach (double num in listLevel)
			{
				bool flag = false;
				foreach (Pipe pipe in listPipe)
				{
					flag = this.CheckPointInPipe(pipe, num, baseDistance);
					if (flag)
					{
						break;
					}
				}
				if (flag)
				{
					list.Add(num);
				}
			}
			list = (from r in list
			orderby r
			select r).ToList<double>();
			return list;
		}

		private bool LayCheckMouth(ref List<Pipe> listPipe, FamilySymbol fs, double levelValue, double baseDistance, XYZ baseVec = null)
		{
			bool flag = false;
			foreach (Pipe pipe in listPipe)
			{
				if (pipe != null)
				{
					flag = this.CheckPointInPipe(pipe, levelValue, baseDistance);
					if (flag)
					{
						flag = this.JudgeSiteCheckMouth(pipe, levelValue + baseDistance / 304.8);
						if (flag)
						{
							flag = this.LayCheckMouth(pipe, fs, levelValue + baseDistance / 304.8, ref listPipe, baseVec);
							break;
						}
					}
				}
			}
			return flag;
		}

		private bool CheckPointInPipe(Pipe pipe, double levelValue, double pntValue)
		{
			bool result = false;
			List<XYZ> pipeEndPoints = this.GetPipeEndPoints(pipe);
			double num = levelValue + pntValue / 304.8;
			if (pipeEndPoints[0].Z < num && pipeEndPoints[1].Z > num)
			{
				result = true;
			}
			return result;
		}

		private bool JudgeSiteCheckMouth(Pipe pipe, double pntValue)
		{
			bool result = false;
			double num = pipe.GetParameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).AsDouble() * 304.8;
			double num2;
			if (num < 51.0)
			{
				num2 = 150.0;
			}
			else if (num < 101.0)
			{
				num2 = 250.0;
			}
			else if (num < 151.0)
			{
				num2 = 350.0;
			}
			else if (num < 201.0)
			{
				num2 = 400.0;
			}
			else
			{
				num2 = 600.0;
			}
			num2 = (num2 / 2.0 + 10.0) / 304.8;
			List<XYZ> pipeEndPoints = this.GetPipeEndPoints(pipe);
			if (pntValue - pipeEndPoints[0].Z > num2 && pipeEndPoints[1].Z - pntValue > num2)
			{
				result = true;
			}
			return result;
		}

		private Pipe riserPipe;

		private Document doc;
	}
}
